package portal.manager.impl;

import static portal.manager.PortalManagerUtils.close;
import static portal.manager.PortalManagerUtils.getBeanManager;
import static portal.manager.PortalManagerUtils.getPortalPanels;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.bsc.bean.BeanManager;
import org.bsc.bean.StoreConstraints;
import org.bsc.bean.metadata.ColumnBean;
import org.bsc.bean.metadata.TableBean;
import org.bsc.bean.osgi.BeanManagerService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

import portal.PortalPanel;
import portal.manager.PortalManagerUtils;
import portal.manager.data.Page;
import portal.manager.data.ServiceBean;
import portal.manager.data.TableBeanEx;
import portal.manager.data.Template;
import portal.manager.data.Template.Variable;
import portal.manager.service.PortalManagerService;

/**
 * 
 * @author Sorrentino
 *
 */
public class PortalManagerServiceImpl implements PortalManagerService {
	private final Logger logger = Logger.getLogger("portal.manager");

	private BundleContext context;
	
	/**
	 * 
	 * @param context
	 */
	public PortalManagerServiceImpl( BundleContext context) {
		this.context = context;
	}

	/**
	 * 
	 */
	public Connection getConnection() throws Exception {
		return PortalManagerUtils.getConnection();
	}

	/**
	 * @throws Exception 
	 * 
	 */
	public TableBean[] getTables() throws Exception {

		ServiceReference ref = context.getServiceReference(BeanManagerService.class.getName());
		BeanManagerService bms = (BeanManagerService) context.getService(ref);
		
		Connection conn = getConnection();
		
		List<TableBean> result = new ArrayList<TableBean>(100);
		
		bms.getTables( conn.getMetaData(), null, "APP", "%", null, result, TableBeanEx.class );
		
		TableBean r[] = new TableBean[ result.size()];
		
		return result.toArray(r);
		
	}

	/**
	 * 
	 */
	public ColumnBean[] getColumns( String schema, String tableName) throws Exception {

		ServiceReference ref = context.getServiceReference(BeanManagerService.class.getName());
		BeanManagerService bms = (BeanManagerService) context.getService(ref);
		
		Connection conn = getConnection();
		
		List<ColumnBean> result = new ArrayList<ColumnBean>(100);
		
		TableBean bean = new TableBean( schema, tableName );
		
		bms.getColumns( conn.getMetaData(), bean, result, ColumnBean.class);

		ColumnBean r[] = new ColumnBean[ result.size()];
		
		return result.toArray(r);
	}

	/**
	 * 
	 * @return
	 */
	public ServiceBean[] getServices() throws Exception {
	
		String className = null;
		String filter = "(bind.protocol=json-rpc)";
		
		try {
			ServiceReference[] refs = context.getServiceReferences( className, filter );
			
			if( null!=refs ) {
				Collection<ServiceBean> result = new ArrayList<ServiceBean>(refs.length);

				for( ServiceReference ref : refs ) {
				
					result.add( ServiceBean.createFromReference(context, ref));
				
				}
			
				return result.toArray( new ServiceBean[result.size()]);
			}
			
		} catch (InvalidSyntaxException e) {
			logger.log( Level.WARNING, "invalid syntax on filter {0}", filter );
		}

		return new ServiceBean[0];
		
	}

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public Template[] getTemplates() throws Exception {
		
		BeanManager<Template> templateMgr = (BeanManager<Template>) getBeanManager( context, "TEMPLATE" );
		BeanManager<Template.Variable> templateVarMgr = (BeanManager<Template.Variable>) getBeanManager( context, "TEMPLATE_VARIABLE" );

		List<Template> result = new ArrayList<Template>(100);
		
		Connection conn = null;
		try {
			conn = getConnection();
			

			templateMgr.findAll(conn, result, null);
			
			for( Template t: result ) {
				List<Template.Variable> var = new ArrayList<Template.Variable>(100);
				
				templateVarMgr.find( conn, var, "${templateId}=?", t.getName());
				
				t.setVariables(var);
				
			}
			
		}
		finally {
			close( conn );
			
		}
		return result.toArray( new Template[ result.size()] );
		
	}

	/**
	 * 
	 */
	public String[] getPanelNames() throws Exception {

		PortalPanel[] panels = getPortalPanels(  context , null ); 
		
		if( null==panels || panels.length==0) return new String[0];
			
		List<String> result = new ArrayList<String>(panels.length);
		
		for( PortalPanel pp : panels ) {
			result.add( pp.getName() );
		}
		
		return result.toArray(new String[panels.length]);

	}

	/**
	 * 
	 */
	@SuppressWarnings("unchecked")
	public Page createPage(String pageName, String templateName, String[] templateVars, String[] values) throws Exception {
		final String method = "Page createPage(String pageName, String templateName, String[] templateVars, String[] values) ";
		
		logger.entering(getClass().getName(), method);
		
		if( null==pageName ) throw new IllegalArgumentException( "parameter page name is null");
		if( null==templateName ) throw new IllegalArgumentException( "parameter template name is null");
		if( null==templateVars ) throw new IllegalArgumentException( "parameter template variables is null");
		if( null==values ) throw new IllegalArgumentException( "parameter panels is null");
		if( values.length != templateVars.length ) throw new IllegalArgumentException( "#template variables are different from #panels ");

		
		BeanManager<Template> templateMgr = (BeanManager<Template>) getBeanManager( context, "TEMPLATE" );
		BeanManager<Template.Variable> templateVarMgr = (BeanManager<Template.Variable>) getBeanManager( context, "TEMPLATE_VARIABLE" );
		BeanManager<Page> pageMgr = (BeanManager<Page>) getBeanManager( context, "PAGE" );
		BeanManager<Page.Variable> pageVarMgr = (BeanManager<Page.Variable>) getBeanManager( context, "PAGE_VARIABLE" );
		
		Page result = null;
		
		Connection conn = null;
		try {
			conn = PortalManagerUtils.getConnection(true);

			Template t = templateMgr.findById(conn, templateName);

			if( null==t ) throw new Exception( "template doesn't exist! " + templateName);

			t.setVariables((List<Variable>) templateVarMgr.find(conn, new ArrayList<Template.Variable>(10), "${templateId}=?", templateName) );
			
			result = new Page( pageName, t );
			
			for( int i=0; i<templateVars.length ; ++i ) {
				result.setPanel(templateVars[i], values[i]);

			}
			
			pageMgr.create(conn, result );
			
			List<Template.Variable> varList = (List<Template.Variable>) result.getVariables();
			
			Page.Variable [] vars =  (Page.Variable[])varList.toArray( new Page.Variable[ varList.size()]);
			
			pageVarMgr.create(conn, vars);
		
			conn.commit();
		}
		catch( Exception e ) {
			conn.rollback();
			logger.log( Level.SEVERE, method, e );
			throw e;
		}
		finally {
			close( conn );
			
		}
		
		logger.exiting(getClass().getName(), method);
		
		return result;
	}

	
	/**
	 * 
	 * @param pageName
	 * @param templateVars
	 * @param values
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public void storePage(String pageName, String[] templateVars, String[] values) throws Exception {

		final String method = "storePage(String pageName, String[] templateVars, String[] values)";
		
		logger.entering(getClass().getName(), method );
		
		if( null==pageName ) throw new IllegalArgumentException( "parameter page name is null");
		if( null==templateVars ) throw new IllegalArgumentException( "parameter template variables is null");
		if( null==values ) throw new IllegalArgumentException( "parameter values is null");
		if( values.length != templateVars.length ) throw new IllegalArgumentException( "#template variables are different from #values ");

		
		BeanManager<Page> pageMgr = (BeanManager<Page>) getBeanManager( context, "PAGE" );
		BeanManager<Page.Variable> pageVarMgr = (BeanManager<Page.Variable>) getBeanManager( context, "PAGE_VARIABLE" );
		
		Connection conn = null;
		try {
			conn = PortalManagerUtils.getConnection(true);
			
			Page p = pageMgr.findById(conn, pageName);

			if( null==p ) throw new Exception( "page doesn't exist! " + pageName);

			pageMgr.store( conn, p );
			
			Page.Variable pv = new Page.Variable();
			for( int i=0; i<templateVars.length; ++i ) {
				
				System.out.printf( "var['%s']=%s\n", templateVars[i], values[i] );
				pv.setId( templateVars[i] );
				pv.setValue( values[i] );
				
				pageVarMgr.store( conn, pv, StoreConstraints.INCLUDE_PROPERTIES, "VALUE");
			}
			
			conn.commit();
		
		} 
		catch( Exception e ) {
			conn.rollback();
			logger.log( Level.SEVERE, method, e );
			throw e;
		}
		finally {
			close( conn );
			
		}

		logger.exiting(getClass().getName(), method );
		
	}

	/**
	 * 
	 */
	public Page[] getPages() throws Exception {
		return portal.manager.PortalManagerUtils.getPages( context );
	}
	
}
